/**
 * request 网络请求工具
 * 更详细的 api 文档: https://github.com/umijs/umi-request/blob/HEAD/README_zh-CN.md
 */
import { extend } from 'umi-request';
import { notification, message } from 'antd';
import { routerRedux } from 'dva/router';
import axios from './axios.min.js';

const codeMessage = {
  200: '服务器成功返回请求的数据。',
  201: '新建或修改数据成功。',
  202: '一个请求已经进入后台排队（异步任务）。',
  204: '删除数据成功。',
  400: '发出的请求有错误，服务器没有进行新建或修改数据的操作。',
  401: '用户没有权限（令牌、用户名、密码错误）。',
  403: '当前角色没有访问此接口的权限',
  404: '发出的请求针对的是不存在的记录，服务器没有进行操作。',
  413: '需要账号密码验证',
  406: '请求的格式不可得。',
  410: '请求的资源被永久删除，且不会再得到的。',
  422: '当创建一个对象时，发生一个验证错误。',
  500: '服务器发生错误，请检查服务器。',
  502: '网关错误。',
  503: '服务不可用，服务器暂时过载或维护。',
  504: '网关超时。',
};
/**
 * 异常处理程序
 */
const errorHandler = (error, res) => {
  const { response } = error;
  console.log('%c RequestError:', 'color:red', error);
  if (response && response.status) {
    const errorText = codeMessage[response.status] || response.statusText;
    const { status, url } = response;
    notification.error({
      message: `请求错误 ${status}: ${url}`,
      description: errorText,
    });
  }
};
/**
 * 配置request请求时的默认参数
 */

const request = extend({
  errorHandler,
  // 默认错误处理
  credentials: 'include', // 默认请求是否带上cookie
  // maxCache: 10, // 最大缓存个数, 超出后会自动清掉按时间最开始的一个.
  //   prefix: '/api/v1', // prefix
  //   suffix: '.json', // suffix
  //   headers: {
  //     some: 'header', // 统一的headers
  //   },
  //   params: {
  //     hello: 'world', // 每个请求都要带上的query参数
  //   },
});
const axReq = axios.create();

let isRefreshing = false;
const reqCache = [];

const getToken = () => {
  const tokenInfo = localStorage.getItem('token');
  let tokenObj = {};
  try {
    tokenObj = JSON.parse(tokenInfo) || {};
  } catch (error) {
    return {};
  }
  return tokenObj;
};

const toLoginPage = () => {
  const { href, origin, pathname } = window.location;
  const params = href.split('redirect=');
  const redirect = decodeURIComponent(params.length === 1 ? params[0] : params[params.length - 1]);
  const codeRedirect = encodeURIComponent(redirect);
  localStorage.clear();
  window.location.replace(`${origin + pathname}#/user/login?redirect=${codeRedirect}`);
};

class RequestCache {
  constructor(url, options) {
    this.url = url;
    this.options = options;
    const This = this;
    this.Promise = new Promise((resolve, reject) => {
      This.resolveBack = resolve;
      This.rejectBack = reject;
    });
  }

  async dispatch() {
    const token = getToken();
    const { url, options } = this;
    const res = await request(url, { ...options, Authorization: token.accessToken });
    this.resolveBack(res);
  }

  deffer() {
    return this.Promise;
  }
}

const cacheRequest = (url, options) => {
  const req = new RequestCache(url, options);
  reqCache.push(req);
  return req;
};

const dispatchAll = () => {
  while (reqCache.length > 0) {
    reqCache.shift().dispatch();
  }
};

const sendRefreshToken = async () => {
  isRefreshing = true;
  let token = getToken();
  const { accessToken: Authorization, refreshToken } = token;
  const { data: res } = await axReq.post(
    '/admin/api/refreshToken',
    { refreshToken },
    {
      headers: { Authorization },
    },
  );
  const { code, data } = res;
  console.log('refreshToken:', data);
  if (code !== '000000') {
    toLoginPage();
  } else {
    token = { ...token, ...data };
    localStorage.setItem('token', JSON.stringify(token));
  }
  isRefreshing = false;
  return true;
};

// request拦截器, 改变url 或 options.
request.interceptors.request.use((url, options) => {
  const token = getToken();
  const { accessToken: Authorization } = token;
  return {
    url,
    options: { ...options, headers: { ...options.headers, Authorization } },
  };
});

request.use(
  async (ctx, next) => {
    const { req } = ctx;
    const { url, options } = req;
    await next();
    try {
      const { res } = ctx;
      const response = await res.clone().json();
      const { code, message: msg } = response;
      console.log('%c request:', 'color:green', res.url);
      console.log('%c response:', 'color:green', response);
      if (code === 'AM4001' || code === 403 || code === '403') {
        toLoginPage();
      } else if (code === 'AM4002' || code === 402 || code === '402') {
        console.log('after cache:', url);
        const cReq = cacheRequest(url, options);
        if (!isRefreshing) {
          await sendRefreshToken();
          dispatchAll();
        }
        ctx.res = await cReq.deffer();
      } else if (code === 'AM3001') {
        message.error(msg);
      }
    } catch (error) {
      console.log('%c error:', 'color:red', error);
    }
  },
  { core: true },
);

// response拦截器
/*
request.interceptors.response.use(async (res, req) => {
  console.log('y=2');
  let data = {};
  try {
    data = await res.clone().json();
    const { code, message: msg } = data;
    console.log('%c request:', 'color:green', res.url);
    console.log('%c response:', 'color:green', data);
    if (code === 'AM4001' || code === 403) {
      // || code === 'AM4002'
      localStorage.clear();
      window.location.href = `#/user/login?redirect=${encodeURIComponent(window.location.href)}`;
    } else if (code === 'AM4002') {
       // token过期
    } else if (code === 'AM3001') {
      message.error(msg);
      return false;
    }
  } catch (error) {
    console.log('%c error:', 'color:red', error);
  }
  return res;
});
*/
export default request;
